/**
    @file
 *  @brief   杆单元
 *  @author  pengtianrui
 *  @date    2024.5.9
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#pragma once
#include "Utility/Algebra/Matrix.h"
#include "Utility/Algebra/Vector3D.h"
#include "Utility/Algebra/Point.h"
#include "DataStructure/Common/Out.h"
#include "DataStructure/Common/Id.h"
#include "DataStructure/Common/Real.h"
#include "DataStructure/Input/Material/MaterialDef.h"
#include "DataStructure/Input/Element/CONRODData.h"
#include "../Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN

class ElementCalculator_DECLSPEC RodCalculator : public SG::FEMSolver::Element::IElementCalculator
{
public:
    RodCalculator () = default;
    virtual ~RodCalculator () = default;

    /** @brief 计算单元拉压刚度矩阵
     *  @param [in]  L         单元长度
     *  @param [in]  material  材料属性
     *  @param [in]  S         截面面积
     *  @param [in]  T         坐标转换矩阵
     *  @param [out] kg        位移输出坐标系下单元拉压刚度矩阵
     */
    static void ComputeLinkStiffness
    (
    const SG::DataStructure::Common::Real            L,
    const SG::DataStructure::FEM::IsotropicMaterial& material,
    const SG::DataStructure::Common::Real            S,
    const SG::Algebra::Matrixd&                      T,
    _OUT SG::Algebra::Matrixd&                       kg
    );

    /** @brief 计算单元扭转刚度矩阵
     *  @param [in]  L         单元长度
     *  @param [in]  material  材料属性
     *  @param [in]  J         扭转常数
     *  @param [in]  T         坐标转换矩阵
     *  @param [out] kt        位移输出坐标系下单元扭转刚度矩阵
     */
    static void ComputeTorsionStiffness
    (
    const SG::DataStructure::Common::Real            L,
    const SG::DataStructure::FEM::IsotropicMaterial& material,
    const SG::DataStructure::Common::Real            J,
    const SG::Algebra::Matrixd&                      T,
    _OUT SG::Algebra::Matrixd&                       kt
    );

    void ComputeTemperatureLoad
    (
    const SG::DataStructure::FEM::IsotropicMaterial& material,
    const SG::DataStructure::Common::Real            S,
    const SG::DataStructure::Common::Real            deltaT,
    const SG::Algebra::Matrixd&                      T,
    _OUT SG::Algebra::Matrixd&                       Pe0
    );

    /** @brief 计算位移坐标系单元集中质量矩阵
     *  @param [in]  m       1/2 的单元质量（包含非结构质量部分）
     *  @param [out] lumpedM 位移坐标系单元集中质量矩阵
     */
    static void ComputeLumpMass
    (
    const SG::DataStructure::Common::Real m,
    _OUT SG::Algebra::Matrixd&            lumpedM
    );

    /** @brief 计算位移坐标系单元耦合质量矩阵
     *  @param [in]  m              1/2 的单元质量（包含非结构质量部分）
     *  @param [in]  xVec           Basic 坐标系下杆单元的单位方向矢量
     *  @param [in]  dispCoordIdSet 单元节点的位移输出坐标系 Id
     *  @param [in]  pointSet       单元节点在 Basic 坐标系下的坐标
     *  @param [out] coupledM       位移坐标系单元耦合质量矩阵
     */
    static void ComputeCoupleMass
    (
    const SG::DataStructure::Common::Real     m,
    const SG::Algebra::Vector3D&              xVec,
    const SG::DataStructure::Common::IdArray& dispCoordIdSet,
    const SG::Algebra::PointArray&            pointSet,
    _OUT SG::Algebra::Matrixd&                coupledM
    );

    /**
     * @brief    计算单元轴向应变
     * 
     * @param    [in]  TEle 总体坐标到局部坐标转换矩阵
     * @param    [in]  eleTranslationalDisplacement 总体坐标系结点位移
     * @param    [in]  L 单元长度
     * @param    [in]  coeffMatrix 计算应变的差值矩阵
     * @param    [in]  material 材料信息
     * @param    [in]  rodData 单元信息
     * @param    [out] eleAxialStrain 单元轴向应变
     *  @param    [out] eleAxialStress 单元轴向应力
     * *@param    [out] eleAxialForce 单元轴向内力
     */
    static void ComputeAxialForce (const SG::Algebra::Matrixd&                      TEle,
                                   const SG::Algebra::Matrixd&                      eleTranslationalDisplacement,
                                   const SG::DataStructure::Common::Real&           L,
                                   const SG::Algebra::Matrixd&                      coeffMatrix,
                                   const SG::DataStructure::FEM::IsotropicMaterial& material,
                                   const SG::DataStructure::FEM::CONRODData&        rodData,
                                   _OUT SG::DataStructure::Common::Real& eleAxialStrain,
                                   _OUT SG::DataStructure::Common::Real& eleAxialStress,
                                   _OUT SG::DataStructure::Common::Real& eleAxialForce);

    virtual void Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void DataRecovery (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int subcaseId, SG::DataStructure::Common::Real time, const std::vector<SG::DataStructure::Common::Real>& globalDisplacement) override;
    virtual void ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;

    static ElementCalculatorSP Create () {return std::make_shared<RodCalculator> ();}
    
private:
    SG::DataStructure::FEM::ElementTypes m_type;
};

SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE